<template>
  <div>
    <h1>计算属性和监听</h1>
    <input type="text" v-model="user.firstName"><br>
    <input type="text" v-model="user.lastName"><br>
    <input type="text" v-model="user.child.lastName"><br>
    <input type="text" v-model="fullName"><br>
    <input type="text" v-model="fullName1"><br>
    <input type="text" v-model="fullName2"><br>
    <input type="text" v-model="fullName3"><br>
  </div>
  <h1>在vue3.x当中需不需要根标签</h1>
  <!-- 
  在vue3的组件当中写时不需要根标签，是因为在内部插入了Fragment（片段）
  Fragment是一个虚拟元素

  使用fragment虚拟元素的好处：减少了标签层级 减小内存占用

  fragment 使用的window中的document当中的createDocumentFragment

  1.createDocumentFragment()方法，是用来创建一个虚拟的节点对象，或者说，是用来创建文档碎片节点。它可以包含各种类型的节点，在创建之初是空的。
  2.DocumentFragment节点不属于文档树，继承的parentNode属性总是null。它有一个很实用的特点，当请求把一个DocumentFragment节点插入文档树时，插入的不是DocumentFragment自身，而是它的所有子孙节点，即插入的是括号里的节点。这个特性使得DocumentFragment成了占位符，暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作。 
  另外，当需要添加多个dom元素时，如果先将这些元素添加到DocumentFragment中，再统一将DocumentFragment添加到页面，会减少页面渲染dom的次数，效率会明显提升。

  体现出以下几点：
  1.虚拟的节点对象，可包含各类型的节点，节点的各种属性和方法
  2.使用fragment进行节点的插入时，不是自身而是它的子元素
  3.将子元素统一都插入到页面，减少DOM操作，减少重排 重绘 回流，效率会明显提升
  -->
</template>

<script lang="ts">
import { defineComponent,reactive,computed,ref, watch, watchEffect } from 'vue'

export default defineComponent({
  setup () {
    // vue3当中的计算属性的用法 get  set
    // 计算属性的get方法
    const user=reactive({
      firstName:'shengnan',
      lastName:'yan',
      child:{
        firstName:'xiaoshengnan',
        lastName:'xiaoyan'
      }
    })
    // 需求 根据firstName lastName的值得到全名 fullName
    const fullName=computed(()=>{
      return user.firstName +'--'+ user.lastName
    })
    console.log(fullName)
    // set
    // 当计算属性得到的值发生变化  就会触发set属性  参数更新过后的
    const fullName1=computed({
      get(){
        return user.firstName +'--'+ user.lastName
      },
      set(value:string){
        // Object is of type 'unknown'
        console.log(value)
        const arr=value.split('-')
        // 字符串通过split分割后得到的值是数组
        user.firstName=arr[0]
        user.lastName=arr[1]
      }
    })

    // watch
    const fullName2=ref('')
    // watch(user,()=>{
    //   fullName2.value=user.firstName+'-'+user.child.lastName
    // },{
    //   deep:true, //深度监视
    //   immediate:true  //立即触发
    // })
    // console.log(fullName1)
    // watch(fullName2,(newValue:string,oldValue)=>{
    //   console.log(newValue)
    //   console.log(oldValue)
    //   let arr=newValue.split('-')
    //   user.firstName=arr[0]
    //   user.child.lastName=arr[1]
    // })

    // 现在是watch一次监听一个数据类型  可以写多次  还有一种语法 一个watch可以监听多个数据
    // 当是基本数据类型时 可以直接写  当是引用数据类型时 就需要使用函数的方法写
    // 当watch监听多个时 其中任何一个发生变化 都会触发watch的回调函数
    watch([fullName2,()=>user.firstName,()=>user.lastName],(values,oldValues)=>{
      console.log(values)
      console.log(oldValues)
      // 分情况而定写多种逻辑
      // 如果firstName和lastName发生变化 获取新的fullName2
      if(values[1] != oldValues[1] || values[2] != oldValues[2]){
        fullName2.value=values[1] +'-'+ values[2]
      }
      else if(values[0] != oldValues[1]){
        let arr = values[0].split('-')
        user.firstName=arr[0]
        user.lastName=arr[1]
      }
      // 并列的要不执行if 要不执行else if
      // 如果fullName2发生变化  获取新的firstName和lastName 监听的也有firstName和lastName
      // if(values[0] != oldValues[1]){
      //   let arr = values[0].split('-')
      //   user.firstName=arr[0]
      //   user.lastName=arr[1]
      // }
      // 当fullName2发生变化 更新firstName和lastName
      // 这两个if条件是没有关系的 只有符合其中if的条件的 他们的内部逻辑就会发生
    })


    // watchEffect
    const fullName3=ref('')
    watchEffect(()=>{
      fullName3.value=user.firstName+'-'+user.lastName
    })
    // ref 获取DOM元素
    return {
      user,
      fullName,
      fullName1,
      fullName2,
      fullName3,
    }
  }
})
</script>

<style scoped>

</style>